﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using Model.Entities;
using Model.Enums;
using Model.EventArgs;
using log4net;

namespace CardDownloader
{
    public partial class FormDownloadListCard : Form
    {
        public List<CardInformation> CardInfos { get; set; }
        public string Url { get; set; }
        private event EventHandler<EventArgs> OnDownloadListCardFinish;
        private event EventHandler<CardStatusChangedEventArgs> OnCardStatusChanged;
        private static readonly ILog log = LogManager.GetLogger(typeof (FormDownloadListCard));
        public int PageIndex { get; set; }
        public int CurrentPage { get; set; }
        public int ItemPerPage { get; set; }
        public int TotalPage { get; set; }
        public StringBuilder Builder { get; set; }
        public List<CardInformation> CurrentDownloading { get; set; }
        public int DownloadFilesAtTheSameTime { get; set; }
        public string _selectedCardStatus;
        

        public FormDownloadListCard()
        {
            InitializeComponent();
            Url = txtStartPage.Text;
            CardInfos = new List<CardInformation>();
            Builder = new StringBuilder();
            PageIndex = 1;
            CurrentPage = 1;
            TotalPage = 1;
            ItemPerPage = 50;
            DownloadFilesAtTheSameTime = 4;
            cboCardStatus.SelectedIndex = 0;
            OnDownloadListCardFinish += FormDownloadListCard_OnDownloadListCardFinish;
            OnCardStatusChanged += FormDownloadListCard_OnCardStatusChanged;
            Disposed += FormDownloadListCard_Disposed;
        }

        void FormDownloadListCard_Disposed(object sender, EventArgs e)
        {
            OnDownloadListCardFinish -= FormDownloadListCard_OnDownloadListCardFinish;
            OnCardStatusChanged -= FormDownloadListCard_OnCardStatusChanged;
        }

        void FormDownloadListCard_OnCardStatusChanged(object sender, CardStatusChangedEventArgs e)
        {
            if (InvokeRequired)
                BeginInvoke(new MethodInvoker(()=>ProcessOnCardStatusChanged(e)));
            else
                ProcessOnCardStatusChanged(e);
        }

        private void ProcessOnCardStatusChanged(CardStatusChangedEventArgs e)
        {
            try
            {
                if (e.CardStatus == CardStatus.Downloaded)
                    txtLog.Text = Builder.ToString();
                UpdateNavigator();
            }
            catch (Exception ex)
            {
                log.Error(ex);
            }
        }


        void FormDownloadListCard_OnDownloadListCardFinish(object sender, EventArgs e)
        {
            try
            {
                if (InvokeRequired)
                    BeginInvoke(new MethodInvoker(ProcessOnDownloadListCardFinish));
                else
                    ProcessOnDownloadListCardFinish();
            }
            catch (Exception ex)
            {
                log.Error(ex);
            }
        }

        private void ProcessOnDownloadListCardFinish()
        {
            try
            {
                txtStartPage.Text = Url;
                if(!string.IsNullOrEmpty(Url))
                    Task.Factory.StartNew(() => DownloadListCard(Url));
                else
                {
                    UpdateNavigator();
                    Builder.Insert(0, string.Format("{0}: Finish Download List Card{1}", DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss"), Environment.NewLine));
                    btnDownloadAllCard.Enabled = true;
                }
                txtLog.Text = Builder.ToString();
            }
            catch (Exception ex)
            {
                log.Error(ex);
            }
        }

        private void btnGo_Click(object sender, EventArgs e)
        {
            btnDownloadAllCard.Enabled = false;
            txtLog.Text = string.Empty;
            CardInfos.Clear();
            Builder.Insert(0,string.Format("{0}: Start Download List Card{1}", DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss"),Environment.NewLine));
            Task.Factory.StartNew(() => DownloadListCard(Url));
        }

        private void DownloadListCard(string url)
        {
            try
            {
                var result = Utils.DownloadListCard(ref url, PageIndex);
                CardInfos.AddRange(result);
                Builder.Insert(0, string.Format("{0}: Finish Download List Card From URL {1}{2}", DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss"), Url, Environment.NewLine));
                Url = url;
                PageIndex++;
                if(OnDownloadListCardFinish != null)
                    OnDownloadListCardFinish(this,new EventArgs());
            }
            catch (Exception ex)
            {
                log.Error(ex);
            }
        }

        private void FormDownloadListCard_Load(object sender, EventArgs e)
        {
            if(File.Exists("Data.dat"))
            {
                using (FileStream fileStream = new FileStream("Data.dat",FileMode.Open))
                {
                    BinaryFormatter binaryFormatter = new BinaryFormatter();
                    CardInfos = (List<CardInformation>) binaryFormatter.Deserialize(fileStream);
                    var attributes = CardInfos.Where(c => c.isMonster && string.IsNullOrEmpty(c.Attribute));
                    foreach (var attribute in attributes)
                    {
                        txtLog.AppendText(attribute.Url + Environment.NewLine);
                    }
                }
            }
            UpdateNavigator();
        }

        private void UpdateNavigator()
        {
            try
            {
                var result = CardInfos.
                    Where(c =>
                    {
                        if (_selectedCardStatus == "All")
                            return true;
                        return c.Status == _selectedCardStatus;
                    }).
                    Select(c => new
                    {
                        c.CardName, c.Url, c.Status
                    });
                int count = result.Count();
                TotalPage = (int)Math.Ceiling((decimal)count / ItemPerPage);
                if (TotalPage == 0) TotalPage = 1;
                dgvListCard.DataSource = result.Skip((CurrentPage - 1) * ItemPerPage).Take(ItemPerPage).ToList();
                
                lbPage.Text = string.Format("Page: {0}/{1}", CurrentPage, TotalPage);
                btnFirst.Enabled = CurrentPage != 1;
                btnPrevious.Enabled = CurrentPage > 1;
                btnNext.Enabled = CurrentPage < TotalPage;
                btnLast.Enabled = CurrentPage != TotalPage;
            }
            catch (Exception ex)
            {
                log.Error(ex);
            }
        }

        private void btnPrevious_Click(object sender, EventArgs e)
        {
            CurrentPage = CurrentPage - 1;
            UpdateNavigator();
        }

        private void btnNext_Click(object sender, EventArgs e)
        {
            CurrentPage = CurrentPage + 1;

            UpdateNavigator();
        }

        private void btnFirst_Click(object sender, EventArgs e)
        {
            CurrentPage = 1;
            UpdateNavigator();
        }

        private void btnLast_Click(object sender, EventArgs e)
        {
            CurrentPage = TotalPage;
            UpdateNavigator();
        }

        private void txtGoTo_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (!char.IsNumber(e.KeyChar))
                e.Handled = true;
        }

        private void btnGoTo_Click(object sender, EventArgs e)
        {
            int pageToGo = int.Parse(txtGoTo.Text);
            if (pageToGo > TotalPage)
                pageToGo = TotalPage;
            if (pageToGo == 0)
                pageToGo = 1;
            CurrentPage = pageToGo;
            txtGoTo.Text = pageToGo.ToString();
            UpdateNavigator();
        }

        private void btnDownloadAllCard_Click(object sender, EventArgs e)
        {
            try
            {
                btnDownloadAllCard.Enabled = false;
                Task.Factory.StartNew(DownloadAllCard);
            }
            catch (Exception ex)
            {
                log.Error(ex);
            }
        }

        private void DownloadAllCard()
        {
            try
            {
//                if (CurrentDownloading == null)
//                    CurrentDownloading = new List<CardInformation>();
                while (CardInfos.Count(ci => ci.CardStatus == CardStatus.NotDownload) > 0)
                {
                    CardInformation cardInformation = CardInfos.FirstOrDefault(ci => ci.CardStatus == CardStatus.NotDownload);
                    if (cardInformation == null) continue;
                    cardInformation.CardStatus = CardStatus.Downloading;
                    if(OnCardStatusChanged!=null)
                        OnCardStatusChanged(this,new CardStatusChangedEventArgs{CardStatus = CardStatus.Downloading});
                    Utils.DownloadCard(cardInformation.Url, cardInformation);
                    Thread.Sleep(60);
                    cardInformation.CardStatus = CardStatus.Downloaded;
                    if (OnCardStatusChanged != null)
                        OnCardStatusChanged(this, new CardStatusChangedEventArgs { CardStatus = CardStatus.Downloaded });
                    Builder.Insert(0, string.Format("{0}: Finish Load Card [{1}] {2}{3}",
                                                    DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss"), CardInfos.IndexOf(cardInformation) + 1, cardInformation.CardName,
                                                    Environment.NewLine));
                }
                if(InvokeRequired)
                    BeginInvoke(new MethodInvoker(() => btnSave.Enabled = true));
                else
                    btnSave.Enabled = true;
            }
            catch (Exception ex)
            {
                log.Error(ex);
            }
        }

        private void cboCardStatus_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                _selectedCardStatus = cboCardStatus.SelectedItem.ToString();
                CurrentPage = 1;
                UpdateNavigator();
            }
            catch (Exception ex)
            {
                log.Error(ex);
            }
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            try
            {
                FileStream fileStream = new FileStream("Data.dat",FileMode.OpenOrCreate);
                BinaryFormatter binaryFormatter = new BinaryFormatter();
                binaryFormatter.Serialize(fileStream, CardInfos);
                MessageBox.Show("Save to file Successfull");
                fileStream.Close();
            }
            catch (Exception ex)
            {
                log.Error(ex);
            }
        }

    }
}
